/**
 * Copyright (C) 2010 Cloudfarming <info@cloudfarming.nl>
 *
 * Licensed under the Eclipse Public License - v 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package nl.cloudfarming.client.db.test;



import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Deze klasse levert een implementatie van het Hibernate Thread Local session
 * register. Ieder actief thread in de JVM kan via dit statische object een
 * specifieke Hibernate session aanvragen en sluiten. Klasse fungeert als een
 * singleton.
 *
 * @author Peter Schuler, Merijn Zengers
 */
public class JPASessionLocator {

    /**
     * De referentie naar een Commons Log voor logging.
     */
    private static Logger log = LoggerFactory.getLogger(JPASessionLocator.class);
    /**
     * Referentie naar de Session factory.
     */
    private static EntityManagerFactory entityManagerFactory = null;
    /**
     * De threadlocal instantie voor het opslaan van de gegistreerde sessions.
     */
    private static final ThreadLocal<EntityManager> sessionMap = new ThreadLocal<EntityManager>();

    /**
     * Static code blok zorgt ervoor dat de Hibernate SessionFactory wordt
     * aangemaakt zodra deze klasse geladen wordt.
     */
    static {
        try {
            entityManagerFactory = Persistence.createEntityManagerFactory("test");
            //jdbc:derby:/tmp/cloudfarming-db;create=true
        } catch (Exception ex) {
            log.info("Creation of  EntityManagerFactory failed.", ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

  
    /**
     * Private default constructor voorkomt instantieren van deze klasse.
     */
    private JPASessionLocator() {
    }

    public static void init(){

    }

    /**
     * Functie retouneert een per aanroepend thread een unieke Hibernate
     * Session. De eerste keer dat een thread deze functie aanroept wordt er een
     * nieuw Hibernate session gestart. Het starten van een transactie wordt
     * overgelaten aan de aanroeper.
     *
     * @return de huidige Hibernate Session voor dit thread.
     */
    public static EntityManager getEntityManager() {
        EntityManager retValue = sessionMap.get();

        if (retValue == null) {
            log.debug("New EntityManager linked to  thread "
                    + Thread.currentThread());

//			try {
//				Context ctx = new InitialContext();
//				retValue = (EntityManager) ctx.lookup("java:comp/env/persistence/em");
//			} catch (NamingException e) {
//				throw new IllegalStateException("NamingException",e);
//			}

            retValue = entityManagerFactory.createEntityManager();
            sessionMap.set(retValue);
        }

        log.debug("EntityManager linked to thread " + Thread.currentThread()
                + "requested.");

        return retValue;
    }

    /**
     * Functie sluit het actieve Hibernate voor het aanroepende thread. Als er
     * een actieve transactie wordt gevonden, wordt deze ongedaan gemaakt
     * middels een aanroep naar rollback().
     */
    public static void closeEntityManager() {
        EntityManager entityManager = sessionMap.get();

        if (entityManager != null) {
            log.debug("EntityManager closed for thread "
                    + Thread.currentThread());

            if (entityManager.getTransaction().isActive()) {
                log.debug("EntityManager linked to thread "
                        + Thread.currentThread()
                        + " contains an open transaction! Rollback executed.");
                entityManager.getTransaction().rollback();
            }

            entityManager.close();
        } else {
            log.debug("There was no EntityManager linked to the thread "
                    + Thread.currentThread() + ".");
        }
        sessionMap.set(null);
    }

    /**
     * Functie geeft aan of dit thread al een actieve HibernateSession heeft.
     *
     * @return true als dit thread over een actieve session beschikt.
     */
    public static boolean hasEntityManager() {
        EntityManager session = sessionMap.get();
        return session != null;
    }
}
